export type Animation =
    'bounce'
    | 'flash'
    | 'pulse'
    | 'rubberBand'
    | 'shakeX'
    | 'shakeY'
    | 'headShake'
    | 'swing'
    | 'tada'
    | 'wobble'
    | 'jello'
    | 'heartBeat'
    | 'backInDown'
    | 'backInLeft'
    | 'backInRight'
    | 'backInUp'
    | 'backOutDown'
    | 'backOutLeft'
    | 'backOutUp'
    | 'backOutRight'
    | 'bounceIn'
    | 'bounceInDown'
    | 'bounceOutDown'
    | 'bounceInLeft'
    | 'bounceOutLeft'
    | 'bounceInRight'
    | 'bounceOutUp'
    | 'bounceOutRight'
    | 'bounceInUp'
    | 'bounceOut'
    | 'fadeIn'
    | 'fadeInDown'
    | 'fadeInDownBig'
    | 'fadeInLeft'
    | 'fadeInLeftBig'
    | 'fadeInRight'
    | 'fadeInRightBig'
    | 'fadeInUp'
    | 'fadeInUpBig'
    | 'fadeInTopLeft'
    | 'fadeInTopRight'
    | 'fadeInBottomLeft'
    | 'fadeInBottomRight'
    | 'flip'
    | 'flipInX'
    | 'flipInY'
    | 'flipOutX'
    | 'flipOutY'
    | 'lightSpeedInRight'
    | 'lightSpeedInLeft'
    | 'lightSpeedOutRight'
    | 'lightSpeedOutLeft'
    | 'rotateIn'
    | 'rotateInDownLeft'
    | 'rotateInDownRight'
    | 'rotateInUpLeft'
    | 'rotateInUpRight'
    | 'rotateOut'
    | 'rotateOutDownLeft'
    | 'rotateOutDownRight'
    | 'rotateOutUpLeft'
    | 'rotateOutUpRight'
    | 'hinge'
    | 'jackInTheBox'
    | 'rollIn'
    | 'rollOut'
    | 'zoomIn'
    | 'zoomInDown'
    | 'zoomInLeft'
    | 'zoomInRight'
    | 'zoomInUp'
    | 'zoomOut'
    | 'zoomOutDown'
    | 'zoomOutLeft'
    | 'zoomOutRight'
    | 'zoomOutUp'
    | 'slideInDown'
    | 'slideInLeft'
    | 'slideInRight'
    | 'slideInUp'
    | 'Sliding exits'
    | 'slideOutDown'
    | 'slideOutLeft'
    | 'slideOutRight'
    | 'slideOutUp'

export const animate = (elementQuery: string, animation: Animation, prefix: string = 'animate__') => {
    return new Promise<void>((resolve, reject) => {
        const animationName = `${prefix}${animation}`;
        const node = document.querySelector(elementQuery);
        if (node === null) {
            reject();
            return;
        }
        if (!node.classList.contains(`${prefix}animated`)) {
            node.classList.add(`${prefix}animated`, animationName);
        }

        function handleAnimationEnd(event: Event) {
            event.stopPropagation();
            if (node === null) {
                reject();
                return;
            }
            node.classList.remove(`${prefix}animated`, animationName);
            resolve();
        }

        node.addEventListener('animationend', handleAnimationEnd, {once: true});
    });
}